
package com.base.pay.wx;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.base.pay.MFramePayType;
import com.base.pay.MPayType;
import com.base.pay.PayMethod;
import com.base.pay.wx.client.TenpayHttpClient;
import com.base.pay.wx.model.*;
import com.base.pay.wx.util.*;
import com.base.util.JSONUtils;
import com.base.util.XMLUtils;
import com.github.sd4324530.fastweixin.util.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

/**
 * 微信预支付订单号
 * @author sun
 *
 */
public class WxPrepay {
	private static Logger logger = LoggerFactory.getLogger(WxPrepay.class);
	private static TenpayHttpClient client;
	
	static{
		client = new TenpayHttpClient();
	}

	private static final String unifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
	
	private static final String refundorder = "https://api.mch.weixin.qq.com/secapi/pay/refund";
	
	private static final String refundquery = "https://api.mch.weixin.qq.com/pay/refundquery";
	//企业付款
	private static final String transfers = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
	//查询企业付款
	private static final String gettransferinfo = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
	//发放普通红包
	private static final String sendredpack = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
	//查询红包记录
	private static final String gethbinfo = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo";
	
	private static String[] WAP_PARAMS = new String[]{"appid","noncestr","package","prepayid","sign","timestamp"};
    
    @SuppressWarnings("unchecked")
    private static String getPrepayId(SortedMap<String, String> params){
    	try {
			String result = "";
			if (client.callHttpPost(unifiedorder, getXml(params))){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return map.get("prepay_id");
			}
		} catch (Exception e) {
			
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
    private static String getCodeUrl(SortedMap<String, String> params){
    	try {
			String result = "";
			if (client.callHttpPost(unifiedorder, getXml(params))){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return map.get("code_url");
			}
		} catch (Exception e) {
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private static WxHbReturn hbReturn(SortedMap<String, String> params){
		return hbReturn(params,ConstantUtil.WEB_CERT_FILE);
    }

    @SuppressWarnings("unchecked")
	private static WxHbReturn hbReturn(SortedMap<String, String> params, String file){
    	try {
    		String result = "";
    		SSLContext ssl = ClientCustomSSL.init(file, params.get("mch_id"));
    		if (client.callHttpPost(sendredpack, getXml(params),ssl)){
				result = client.getResContent();
				logger.debug(result);
//				Map<String, String> map = XMLUtil.doXMLParse(result);
//				logger.info("xml2map:{}",JSONUtil.toJson(map));
				return XMLUtils.deserialize(result,WxHbReturn.class);
//				return JSONUtils.deserialize(JSONUtil.toJson(map), WxHbReturn.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private static WxHbInfo hbQuery(SortedMap<String, String> params){
    	return hbQuery(params,ConstantUtil.WEB_CERT_FILE);
    }
    
    @SuppressWarnings("unchecked")
	private static WxHbInfo hbQuery(SortedMap<String, String> params, String file){
    	try {
    		String result = "";
    		SSLContext ssl = ClientCustomSSL.init(file, params.get("mch_id"));
    		if (client.callHttpPost(gethbinfo, getXml(params),ssl)){
				result = client.getResContent();
				logger.debug(result);
//				Map<String, String> map = XMLUtil.doXMLParse(result);
//				return JSONUtils.deserialize(JSONUtils.serialize(map), WxHbInfo.class);
				return XMLUtils.deserialize(result,WxHbInfo.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private static WxTransferReturn transferReturn(SortedMap<String, String> params){
    	return transferReturn(params,ConstantUtil.WEB_CERT_FILE);
    }
    
    @SuppressWarnings("unchecked")
	private static WxTransferReturn transferReturn(SortedMap<String, String> params, String file){
    	try {
    		String result = "";
    		SSLContext ssl = ClientCustomSSL.init(file, params.get("mchid"));
    		if (client.callHttpPost(transfers, getXml(params),ssl)){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return JSONUtils.deserialize(JSONUtils.serialize(map), WxTransferReturn.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private static WxTransferInfo transferQuery(SortedMap<String, String> params){
    	return transferQuery(params,ConstantUtil.WEB_CERT_FILE);
    }
    
    @SuppressWarnings("unchecked")
	private static WxTransferInfo transferQuery(SortedMap<String, String> params, String file){
    	try {
    		String result = "";
    		SSLContext ssl = ClientCustomSSL.init(file, params.get("mch_id"));
    		if (client.callHttpPost(gettransferinfo, getXml(params),ssl)){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return JSONUtils.deserialize(JSONUtils.serialize(map), WxTransferInfo.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	private static WxRefundReturn refundReturn(SortedMap<String, String> params, String file){
    	try {
    		String result = "";
    		SSLContext ssl = ClientCustomSSL.init(file, params.get("mch_id"));
    		if (client.callHttpPost(refundorder, getXml(params),ssl)){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return JSONUtils.deserialize(JSONUtils.serialize(map), WxRefundReturn.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
    private static WxRefundQuery refundQuery(SortedMap<String, String> params){
    	try {
    		String result = "";
    		if (client.callHttpPost(refundquery, getXml(params))){
				result = client.getResContent();
				logger.debug(result);
				Map<String, String> map = XMLUtil.doXMLParse(result);
				return JSONUtils.deserialize(JSONUtils.serialize(map), WxRefundQuery.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    @SuppressWarnings("rawtypes")
	private static String getXml(SortedMap<String, String> params){
    	String sign = createSign(params);
    	params.remove("key");
    	params.put("sign", sign);
    	StringBuffer sb = new StringBuffer();
    	sb.append("<xml>");
    	Set set = params.entrySet();
    	Iterator it = set.iterator();
    	while (it.hasNext()) {
			Map.Entry object = (Map.Entry) it.next();
			String k = (String)object.getKey();
			String v = (String)object.getValue();
			if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)){
				sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
			}else {
				sb.append("<"+k+">"+v+"</"+k+">");
			}
		}
    	sb.append("</xml>");
    	return sb.toString();
    }
    
    @SuppressWarnings("rawtypes")
    public static String createSign(SortedMap<String, String> params){
    	StringBuffer sb = new StringBuffer();
		Set es = params.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			if(null != v && !"".equals(v) 
					&& !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + params.get("key"));
		
		String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();
		
		return sign;
    }
    
    public static boolean isValiSign(SortedMap<String, String> params){
    	String sign = (String)params.get("sign").toUpperCase();
    	return createSign(params).equals(sign);
    }
    
	/**
	 * 微信预支付-app-预支付id
	 */
	public static String wxPrepareId(BigDecimal price,String orderId,String info, String ip, String... backUrl){
		return wxPrepareId(price, orderId, info, ip, MFramePayType.NORMAL_BUY, backUrl);
	}
	
	/**
	 * 微信预支付-app-预支付id
	 */
	public static String wxPrepareId(BigDecimal price, String orderId, String info, String ip, MPayType pay, String... backUrl){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("body", info);
		params.put("out_trade_no", orderId);
		params.put("total_fee", price.multiply(new BigDecimal(100)).intValue()+"");
		params.put("spbill_create_ip", ip);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("attach", pay.toString());
		if (backUrl != null && backUrl.length > 0){
			if (backUrl.length > 3)
				params.put("key", backUrl[3]);
			if (backUrl.length > 2)
				params.put("mch_id", backUrl[2]);
			if (backUrl.length > 1)
				params.put("appid", backUrl[1]); 
			params.put("notify_url", PayMethod.urlToUrl(backUrl[0]));
		}
		return getPrepayId(wxPrepareId(params));
	}
	
	/**
	 * 微信预支付-扫码获取url
	 */
	public static String wxCodeUrl(BigDecimal price,String orderId,String info, String ip, String... backUrl){
		return wxCodeUrl(price, orderId, info, ip, MFramePayType.NORMAL_BUY, backUrl);
	}
	
	/**
	 * 微信预支付-扫码获取url
	 */
	public static String wxCodeUrl(BigDecimal price, String orderId, String info, String ip, MPayType pay, String... backUrl){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("body", info);
		params.put("out_trade_no", orderId);
		params.put("total_fee", price.multiply(new BigDecimal(100)).intValue()+"");
		params.put("spbill_create_ip", ip);
		params.put("notify_url", PayMethod.urlToUrl(ConstantUtil.BACK_URL));
		params.put("trade_type", "NATIVE"); //NATIVE JSAPI WAP  NATIVE(product_id)
		params.put("product_id", UUID.randomUUID().toString().replace("-", ""));
		params.put("device_info", "web");
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("attach", pay.toString());
		if (backUrl != null && backUrl.length > 0){
			if (backUrl.length > 3)
				params.put("key", backUrl[3]);
			if (backUrl.length > 2)
				params.put("mch_id", backUrl[2]);
			if (backUrl.length > 1)
				params.put("appid", backUrl[1]); 
			params.put("notify_url", PayMethod.urlToUrl(backUrl[0]));
		}
		return getCodeUrl(wxWebPrepareId(params));
	}
	
	/**
	 * 微信外部浏览器支付-WAP
	 */
	public static String wxPayUrl(BigDecimal price, String orderId, String info, String ip, MPayType pay, String... backUrl){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("body", info);
		params.put("out_trade_no", orderId);
		params.put("total_fee", price.multiply(new BigDecimal(100)).intValue()+"");
		params.put("spbill_create_ip", ip);
		params.put("notify_url", PayMethod.urlToUrl(ConstantUtil.BACK_URL));
		params.put("trade_type", "WAP"); //NATIVE JSAPI WAP  NATIVE(product_id)
		params.put("product_id", UUID.randomUUID().toString().replace("-", ""));
		params.put("device_info", "wap");
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("attach", pay.toString());
		if (backUrl != null && backUrl.length > 0){
			if (backUrl.length > 3)
				params.put("key", backUrl[3]);
			if (backUrl.length > 2)
				params.put("mch_id", backUrl[2]);
			if (backUrl.length > 1)
				params.put("appid", backUrl[1]); 
			params.put("notify_url", PayMethod.urlToUrl(backUrl[0]));
		}
		params = wxWebPrepareId(params);
		String prePayId = getPrepayId(params);
		String ret = null;
		if (prePayId != null){
			params.put("package", "WAP");
			params.put("prepayid", prePayId);
			try {
				ret = getWapPayUrl(params);
				ret = "weixin：//wap/pay?"+URLEncoder.encode(ret, "utf-8");
			} catch (Exception e) {
				
			}
		}
		return ret;
	}
	
	/**
	 * 微信外部浏览器支付-WAP
	 */
	public static String wxPayUrl(BigDecimal price,String orderId,String info, String ip, String... backUrl){
		return wxPayUrl(price, orderId, info, ip, MFramePayType.NORMAL_BUY,backUrl);
	}
	
	public static String getWapPayUrl(SortedMap<String, String> params) throws UnsupportedEncodingException{
		StringBuffer sb = new StringBuffer();
		Set es = params.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			if(hasWapKey(k)) {
				sb.append(k + "=" + URLEncoder.encode(v, "utf-8") + "&");
			}
		}
		return sb.substring(0, sb.length()-1);
	}
	
	private static boolean hasWapKey(String k){
		for (String str : WAP_PARAMS){
			if (str.equals(k))
				return true;
		}
		return false;
	}
	
	
	/**
	 * 微信JsAPi支付
	 * code微信重定向返回的code
	 * */
	public static String wxJsPrepareId(BigDecimal price,String orderId,String info, String ip, String code){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("body", info);
		params.put("out_trade_no", orderId);
		params.put("total_fee", price.multiply(new BigDecimal(100)).intValue()+"");
		params.put("spbill_create_ip", ip);
		params.put("trade_type", "JSAPI");
		params.put("openid", getOpenid(code));
		return getPrepayId(wxWebPrepareId(params));
	}
	
	/**
	 * 微信预支付
	 * @param map
	 * @return
	 */
	private static SortedMap<String, String> wxPrepareId(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", ConstantUtil.APP_ID);
		params.put("mch_id", ConstantUtil.APP_PARTNER);
		params.put("nonce_str", WXUtil.getNonceStr());
		params.put("body", "微信订单");
		params.put("out_trade_no", WXUtil.getTimeStamp());
		params.put("total_fee", "0.01");
		params.put("spbill_create_ip", "8.8.8.8");
		params.put("notify_url", PayMethod.urlToUrl(ConstantUtil.BACK_URL));
		params.put("trade_type", "APP");
		params.putAll(map);
		return params;
	}
	
	/**
	 * 微信公众号支付
	 */
	public static String wxWapCodeUrl(BigDecimal price, String orderId, String info, String ip, String openId, MPayType pay, String... backUrl){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("body", info);
		params.put("out_trade_no", orderId);
		params.put("total_fee", price.multiply(new BigDecimal(100)).intValue()+"");
		params.put("spbill_create_ip", ip);
		params.put("notify_url", PayMethod.urlToUrl(ConstantUtil.BACK_URL));
		params.put("trade_type", "JSAPI"); //NATIVE JSAPI WAP  NATIVE(product_id)
		params.put("product_id", UUID.randomUUID().toString().replace("-", ""));
		params.put("device_info", "web");
		params.put("openid", openId);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("attach", pay.toString());
		if (backUrl != null && backUrl.length > 0){
			if (backUrl.length > 3)
				params.put("key", backUrl[3]);
			if (backUrl.length > 2)
				params.put("mch_id", backUrl[2]);
			if (backUrl.length > 1)
				params.put("appid", backUrl[1]); 
			params.put("notify_url", PayMethod.urlToUrl(backUrl[0]));
		}
		params = wxWebPrepareId(params);
		return getPrepayId(params);
	}
	
	/**
	 * 微信预支付
	 * @param map
	 * @return
	 */
	public static SortedMap<String, String> wxWebPrepareId(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", ConstantUtil.WEB_APP_ID);
		params.put("mch_id", ConstantUtil.WEB_PARTNER);
		params.put("nonce_str", WXUtil.getNonceStr());
		params.put("body", "微信订单");
		params.put("out_trade_no", WXUtil.getTimeStamp());
		params.put("total_fee", "0.01");
		params.put("spbill_create_ip", "8.8.8.8");
		params.put("notify_url", PayMethod.urlToUrl(ConstantUtil.BACK_URL));
		params.put("trade_type", "WAP");
		params.putAll(map);
		return params;
	}
	
	private static String getOpenid(Map<String, String> params){
		try {
			String result = "";
			if (client.callHttpPost(ConstantUtil.ACCESS_TOKEN_URL, getJsonUrl(params))){
				result = client.getResContent();
				logger.debug(result);
				JSONObject map = JSONObject.parseObject(result);
				return map.getString("openid");
			}
		} catch (Exception e) {
		}
    	return null;
	}
	
	/**
	 * 根据code获取openid
	 */
	public static String getOpenid(String code){
		Map<String, String> params = new HashMap<String, String>();
		params.put("appid", ConstantUtil.WEB_APP_ID);
		params.put("secret", ConstantUtil.WEB_PARTNER);
		params.put("code", code);
		params.put("grant_type", "authorization_code");
		return getOpenid(params);
	}
	
	@SuppressWarnings("rawtypes")
	private static String getJsonUrl(Map<String, String> params){
		StringBuffer sb = new StringBuffer();
		Set es = params.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			sb.append(k + "=" + v + "&");
		}
		return sb.toString();
	}
	
	/**
	 * 申请退款 map组装
	 */
	public static SortedMap<String, String> refundMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("nonce_str", WXUtil.getNonceStr());
		params.put("total_fee", "1");
		params.put("refund_fee", "1");
		params.putAll(map);
		params.put("op_user_id", params.get("mch_id"));
		return params;
	}
	
	/**
	 * 查询退款组装
	 */
	public static SortedMap<String, String> refundQueryMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("nonce_str", WXUtil.getNonceStr());
		params.putAll(map);
		return params;
	}
	
	/**
	 * 订单号退款
	 * @param orderId
	 * @param refundId
	 * @param total
	 * @param refund
	 * @return
	 */
	public static WxRefundReturn refund(String orderId, String refundId, BigDecimal total, BigDecimal refund, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", appId);
		params.put("mch_id", partner);
		params.put("out_trade_no", orderId);
		params.put("out_refund_no", refundId);
		params.put("total_fee", total.multiply(new BigDecimal(100)).intValue()+"");
		params.put("refund_fee", refund.multiply(new BigDecimal(100)).intValue()+"");
		params.put("key", key);
		params = refundMap(params);
		return refundReturn(params,file);
	}
	
	/**
	 * 流水号退款
	 * @param refundId
	 * @param total
	 * @param refund
	 * @return
	 */
	public static WxRefundReturn refundByCode(String tradeNo, String refundId, BigDecimal total, BigDecimal refund, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", appId);
		params.put("mch_id", partner);
		params.put("transaction_id", tradeNo);
		params.put("out_refund_no", refundId);
		params.put("total_fee", total.multiply(new BigDecimal(100)).intValue()+"");
		params.put("refund_fee", refund.multiply(new BigDecimal(100)).intValue()+"");
		params.put("key", key);
		params = refundMap(params);
		return refundReturn(params,file);
	}
	
	/**
	 * 退款查询
	 * type 1:微信订单号 trade_no 2商户订单号 order_id 3商户退款单号 refund_id 4微信退款单号 refund_no
	 */
	public static WxRefundQuery refundQuery(String order, Integer type, String appId, String partner, String key){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", appId);
		params.put("mch_id", partner);
		params.put("key", key);
		switch (type) {
		case 1:
			params.put("transaction_id", order);
			break;
		case 2:
			params.put("out_trade_no", order);
			break;
		case 3:
			params.put("out_refund_no", order);
			break;
		case 4:
			params.put("refund_id", order);
			break;
		default:
			break;
		}
		params = refundQueryMap(params);
		return refundQuery(params);
	}
	
	/**
	 * 企业付款  map组装
	 */
	public static SortedMap<String, String> transferMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("mch_appid", ConstantUtil.WEB_APP_ID);
		params.put("mchid", ConstantUtil.WEB_PARTNER);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("nonce_str", WXUtil.getNonceStr());
		if(map.get("re_user_name") == null){
			params.put("check_name", "NO_CHECK");
		}else{
			params.put("check_name", "FORCE_CHECK");
		}
		params.put("desc", "企业付款");
		params.put("spbill_create_ip", "8.8.8.8");
		params.putAll(map);
		return params;
	}
	
	/**
	 * 企业付款
	 * @param openid
	 * @param transferId
	 * @param amount
	 * @param realName
	 * @param desc
	 * @param appId
	 * @param partner
	 * @param file
	 * @return
	 */
	public static WxTransferReturn transfer(String openid, String transferId, BigDecimal amount, String realName
			, String desc, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("mch_appid", appId);
		params.put("mchid", partner);
		params.put("openid", openid);
		params.put("partner_trade_no", transferId);
		params.put("amount", amount.multiply(new BigDecimal(100)).intValue()+"");
		params.put("re_user_name", realName);
		params.put("desc", desc);
		params.put("key", key);
		params = transferMap(params);
		return transferReturn(params,file);
	}
	
	/**
	 * 企业付款
	 * @param openid
	 * @param transferId
	 * @param amount
	 * @param realName
	 * @param desc
	 * @return
	 */
	public static WxTransferReturn transfer(String openid, String transferId, BigDecimal amount, String realName, String desc){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("openid", openid);
		params.put("partner_trade_no", transferId);
		params.put("amount", amount.multiply(new BigDecimal(100)).intValue()+"");
		params.put("re_user_name", realName);
		params.put("desc", desc);
		params = transferMap(params);
		return transferReturn(params);
	}
	
	/**
	 * 企业付款查询  map组装
	 */
	public static SortedMap<String, String> transferQueryMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", ConstantUtil.WEB_APP_ID);
		params.put("mch_id", ConstantUtil.WEB_PARTNER);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("nonce_str", WXUtil.getNonceStr());
		params.putAll(map);
		return params;
	}
	
	/**
	 * 企业付款查询
	 * @param transferId
	 * @param appId
	 * @param partner
	 * @param key
	 * @param file
	 * @return
	 */
	public static WxTransferInfo transferQuery(String transferId, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", appId);
		params.put("mch_id", partner);
		params.put("partner_trade_no", transferId);
		params.put("key", key);
		params = transferQueryMap(params);
		return transferQuery(params,file);
	}
	
	/**
	 * 企业付款查询
	 * @param transferId
	 * @return
	 */
	public static WxTransferInfo transferQuery(String transferId){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("partner_trade_no", transferId);
		params = transferQueryMap(params);
		return transferQuery(params);
	}
	
	/**
	 * 发普通红包 map组装
	 */
	public static SortedMap<String, String> hbMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("wxappid", ConstantUtil.WEB_APP_ID);
		params.put("mch_id", ConstantUtil.WEB_PARTNER);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("nonce_str", WXUtil.getNonceStr());
		params.put("client_ip", "8.8.8.8");
		params.put("total_num", "1");
		params.putAll(map);
		return params;
	}
	
	/**
	 * 发普通红包
	 * @param code
	 * @param sendName
	 * @param openid
	 * @param amount
	 * @param wishing
	 * @param actName
	 * @param remark
	 * @param sceneId
	 * @param appId
	 * @param partner
	 * @param key
	 * @param file
	 * @return
	 */
	public static WxHbReturn hb(String code, String sendName, String openid, BigDecimal amount, String wishing
			, String actName, String remark, String sceneId, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("wxappid", appId);
		params.put("mch_id", partner);
		params.put("key", key);
		
		params.put("mch_billno", code);//mch_id+yyyymmdd+10位随机数
		params.put("total_amount", amount.multiply(new BigDecimal(100)).intValue()+"");
		params.put("send_name", sendName);
		params.put("wishing", wishing);
		params.put("re_openid", openid);
		params.put("act_name", actName);
		params.put("remark", remark);
		params.put("scene_id", sceneId);
		params = hbMap(params);
		return hbReturn(params,file);
	}
	
	/**
	 * 发普通红包
	 * @param code
	 * @param sendName
	 * @param openid
	 * @param amount
	 * @param wishing
	 * @param actName
	 * @param remark
	 * @param sceneId
	 * @return
	 */
	public static WxHbReturn hb(String code, String sendName, String openid, BigDecimal amount
			, String wishing, String actName, String remark, String sceneId){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("mch_billno", code);//mch_id+yyyymmdd+10位随机数
		params.put("total_amount", amount.multiply(new BigDecimal(100)).intValue()+"");
		params.put("send_name", sendName);
		params.put("wishing", wishing);
		params.put("re_openid", openid);
		params.put("act_name", actName);
		params.put("remark", remark);
		params.put("scene_id", sceneId);
		params = hbMap(params);
		return hbReturn(params);
	}

	/**
	 * 查询红包 map组装
	 */
	public static SortedMap<String, String> hbInfoMap(Map<String, String> map){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", ConstantUtil.WEB_APP_ID);
		params.put("mch_id", ConstantUtil.WEB_PARTNER);
		params.put("key", ConstantUtil.PAY_KEY);
		params.put("nonce_str", WXUtil.getNonceStr());
		params.put("bill_type", "MCHT");
		params.putAll(map);
		return params;
	}
	
	/**
	 * 查询红包
	 * @param code
	 * @param appId
	 * @param partner
	 * @param key
	 * @param file
	 * @return
	 */
	public static WxHbInfo hbInfo(String code, String appId, String partner, String key, String file){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appid", appId);
		params.put("mch_id", partner);
		params.put("key", key);
		params.put("mch_billno", code);
		params = hbInfoMap(params);
		return hbQuery(params,file);
	}
	
	/**
	 * 查询红包
	 * @param code
	 * @return
	 */
	public static WxHbInfo hbInfo(String code){
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("mch_billno", code);
		params = hbInfoMap(params);
		return hbQuery(params);
	}

	public static void main(String[] args) throws Exception{
		String xml = "<xml>\n" +
				"<return_code><![CDATA[SUCCESS]]></return_code>\n" +
				"<return_msg><![CDATA[发放成功]]></return_msg>\n" +
				"<result_code><![CDATA[SUCCESS]]></result_code>\n" +
				"<err_code><![CDATA[SUCCESS]]></err_code>\n" +
				"<err_code_des><![CDATA[发放成功]]></err_code_des>\n" +
				"<mch_billno><![CDATA[3771338nH6]]></mch_billno>\n" +
				"<mch_id><![CDATA[1427224402]]></mch_id>\n" +
				"<wxappid><![CDATA[wxd4d7f6fe73dafd7a]]></wxappid>\n" +
				"<re_openid><![CDATA[obCAmwMBe2y0PT1-vlrQyNPZjalI]]></re_openid>\n" +
				"<total_amount>681</total_amount>\n" +
				"<send_listid><![CDATA[1000041701201802233000101657422]]></send_listid>\n" +
				"</xml>\n";
		Map<String, String> map = XMLUtil.doXMLParse(xml);
		JSONObject json = (JSONObject) JSON.toJSON(map);
		System.out.println(json.toString());
		String ret = JSONUtil.toJson(map);
		System.out.println(ret);
		WxHbReturn hbReturn = JSONUtils.deserialize(ret, WxHbReturn.class);
		System.out.println(JSONUtils.serialize(hbReturn));
		System.out.println("==============");
		WxHbReturn wxHbReturn = XMLUtils.deserialize(xml,WxHbReturn.class);
		System.out.println(JSONUtils.serialize(wxHbReturn));
	}
}
